package com.easyaop.asm.bytecode.asm;

import com.easyaop.asm.bytecode.*;
import com.easyaop.asm.bytecode.asm.methodvisitor.AroundComplieBuilder;
import com.easyaop.asm.bytecode.asm.methodvisitor.DefaultMethodVisitorCompile;
import lombok.Setter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;

import java.util.LinkedList;
import java.util.List;

public class CallMethodVisitor extends MethodVisitor implements Opcodes {
    @Setter
    private MethodInfo target;
    @Setter
    private int offSet;// 把切面变量的位置，偏移下

    private boolean isChangeArgs;
    private boolean isLocal;
    List<TryVo> tryVos =new LinkedList<>();

    public CallMethodVisitor(int api, MethodVisitor methodVisitor) {
        super(api, methodVisitor);
    }

    @Override
    public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {

        if (owner.equals("com/easyaop/api/around/Call") && descriptor.equals("()Ljava/lang/Object;") && name.equals("call")) {
            visitInsn(POP);

            // 回写入参
            if (isChangeArgs) {
                GeneratorAdapter generatorAdapter = new GeneratorAdapter(mv, target.access, target.name, target.descriptor);
                int argsPos = offSet + 2/*args在切面里的位置*/;
                for (int i = 0, len = target.ptypes.length; i < len; i++) {
                    Type type = target.ptypes[i];

                    visitVarInsn(ALOAD, argsPos);
                    visitIntInsn(BIPUSH, i);
                    visitInsn(AALOAD);

                    generatorAdapter.unbox(type);
                    generatorAdapter.storeArg(i);
                }
            }

//            处理call的逻辑
//            visitInsn(ACONST_NULL);
//            if (true)
//                return;


            // 写入业务方法
            DefaultMethodVisitorCompile targetVisitorComplie = AroundComplieBuilder.to(target);

            MethodVisitor methodVisitor = mv;
//            OffsetMethodVisitor offsetMethodVisitor = new OffsetMethodVisitor(api, methodVisitor);
//            offsetMethodVisitor.setOffset(around.maxLocal
//                    - 1); // around没有位置this
//            offsetMethodVisitor.setStart(target.argSize());
//            methodVisitor = offsetMethodVisitor;

            RetTargetMethodVisitor retTargetMethodVisitor = new RetTargetMethodVisitor(api, methodVisitor);
            retTargetMethodVisitor.setTarget(target);
            methodVisitor = retTargetMethodVisitor;


            if (isLocal) {
                methodVisitor = new MethodVisitor(api, methodVisitor) {
                    @Override
                    public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
                    }
                };
            }
            isLocal = true;

//            System.out.println(12345);
//            methodVisitor = new MethodVisitor(api, methodVisitor) {
//                @Override
//                public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
//                    System.out.println("visitTryCatchBlock");
//                    super.visitTryCatchBlock(start, end, handler, type);
//                }
//            };


            MethodVisitorDelTry visitorDelTry = new MethodVisitorDelTry(api, methodVisitor);
            visitorDelTry.trys = tryVos;
            methodVisitor = visitorDelTry;

            targetVisitorComplie.execute(methodVisitor);

            return;
        }

        super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
    }

    @Override
    public void visitInsn(int opcode) {
        super.visitInsn(opcode);
        if (opcode == AASTORE) {
            isChangeArgs = true; // 应该优化成，改了哪个入参，就回写哪个
        }
    }

    @Override
    public void visitVarInsn(int opcode, int varIndex) {
        super.visitVarInsn(opcode, varIndex);
        if(opcode==ASTORE&&varIndex==offSet+2){
            isChangeArgs=true;
        }
    }
}
